'''
Created on 23/09/2013

@author: Hugo sama
'''
import re
from DocumentCollection import DocumentCollection

class SearchManager:
    OPERATOR = 1
    OPERAND = 2
    RIGHT_PARENTHESIS = 3
    LEFT_PARENTHESIS = 4
    NEGATION = '-'
    CONJUCTION = '&'
    DISYUNCTION = '|'
    EMPTY_STACK = '!'
     
    def inputParser(self,inputText):
        replacedText = re.sub("\s*-\s*","-",inputText)
        replacedText = re.sub("\s*&\s*","&",replacedText)
        replacedText = re.sub("\s+y\s+","&",replacedText)
        replacedText = re.sub("\s*\|\s*","|",replacedText)
        replacedText = re.sub("\s+o\s+","|",replacedText)
        replacedText = replacedText.strip()
        replacedText = re.sub("\s+","&",replacedText)
        tokens = re.findall("[\(]|[\)]|[a-zA-Z]+'?[a-zA-Z]?|-|&|\|", replacedText)
        dc = DocumentCollection("")
        return dc.normalizeTokens(tokens)
    
    def infixToPostfix(self,tokens):
        postfix = []
        stack = []
        for currentChar in tokens:
            #dependiendo del tipo de caracter es la operacion
            identifier = self.charIdentifier(currentChar)
            if self.OPERAND == identifier: 
                postfix.append(currentChar);
            if self.LEFT_PARENTHESIS == identifier: 
                stack.append(currentChar)
            if self.RIGHT_PARENTHESIS == identifier: 
                top =  self.EMPTY_STACK if not stack else stack.pop()
                while top != '(':
                    if top == self.EMPTY_STACK:
                        return False
                    else:                            
                        postfix.append(top)
                        top =  self.EMPTY_STACK if not stack else stack.pop()
            if self.OPERATOR == identifier: 
                peek =  self.EMPTY_STACK if not stack else stack[-1]
                if peek == '(' or not stack:
                        stack.append(currentChar)
                        continue
                if self.getPrecedence(currentChar) == self.getPrecedence(peek):
                        postfix.append(stack.pop())
                        stack.append(currentChar)
                        continue                
                if self.getPrecedence(currentChar) > self.getPrecedence(peek):
                        stack.append(currentChar)
                        continue                
                if self.getPrecedence(currentChar) < self.getPrecedence(peek):
                    while self.getPrecedence(currentChar) < self.getPrecedence(peek):
                            postfix.append(stack.pop())
                            peek =  self.EMPTY_STACK if not stack else stack[-1]
                    stack.append(currentChar);
                    continue;          
        while stack:
            postfix.append(stack.pop())
        return postfix
    
    def charIdentifier(self,char):
        identifier = -1;
        if re.match("[a-zA-Z]+",char):
            identifier = self.OPERAND
        if re.match("-|&|=|>|\\|",char):
            identifier = self.OPERATOR
        if char == '(':
            identifier = self.LEFT_PARENTHESIS
        if char == ')':
            identifier = self.RIGHT_PARENTHESIS
        return identifier
    
    def getPrecedence(self,operator):
        precedence = -1
        if operator == self.NEGATION: 
                precedence = 100
        if operator == self.CONJUCTION: 
                precedence = 99
        if operator == self.DISYUNCTION: 
                precedence = 98
        return precedence
    
    def postfixEvaluation(self,postfix,invertedIndex):
        stack = [];
        if not postfix:
            return False
        for currentChar in postfix:
            #dependiendo del tipo de caracter es la operacion
            identifier = self.charIdentifier(currentChar)
            if self.OPERAND == identifier:
                documents = invertedIndex.getDocumentsWithWords([currentChar])
                stack.append(documents)
                continue
            if self.LEFT_PARENTHESIS == identifier: 
                return False
            if self.RIGHT_PARENTHESIS == identifier: 
                return False
            if self.OPERATOR == identifier: 
                if not stack:
                    return False
                if currentChar == self.CONJUCTION:
                        operand1 = stack.pop()
                        if not stack:
                            return False
                        operand2 = stack.pop()
                        intersection = invertedIndex.getIntersection(operand1, operand2)
                        stack.append(intersection)
                        continue
                if currentChar == self.DISYUNCTION:
                        operand1 = stack.pop()
                        if not stack:
                            return False
                        operand2 = stack.pop()
                        union = invertedIndex.getDisjunction(operand1, operand2)
                        stack.append(union)
                        continue        
                if currentChar == self.NEGATION:
                        operand1 = stack.pop()
                        negation = invertedIndex.getNegation(operand1)
                        stack.append(negation)
                        continue  
        result = stack.pop()
        if stack:
            return False
        return result
        
        